import fetch from "isomorphic-fetch"
import {message} from "antd"
import {HOST} from "../project-config"
import {Modal} from "antd"
import AuthenticationError from "./errors/authentication"
import BusinessError from "./errors/business"
import TimeOutError from "./errors/timeout"
import InternalError from "./errors/internal"
import AuthorizationError from "./errors/authorization"


const createTokenHeader = (header) => {
	const headers = !header ? {} : {
		...header
	}
	const token = localStorage.getItem('token')
	if (token) {
		headers['Authorization'] = token
	}
	return headers
}

function resolve(obj, p) {
	if (!obj) return {}
	return Object.entries(obj).map(([k, v]) => {
		const _k = p ? `${p}.${k}` : k
		if (typeof v !== 'object' || v instanceof Array) {
			return {key: _k, value: v}
		} else {
			return resolve(v, _k)
		}
	})
}

function entries(obj) {
	const es = resolve(obj)
	return es ? es.flat(Infinity) : []
}

function createParamString(obj) {
	return entries(obj).map(({key, value}) => `${key}=${value}`).join('&')
}


const networkResponse = (fetchPromise, errorHandler) => {
	const promise = fetchPromise
		.then(async response => {
			if (response.status === 401) {
				const json = await response.json() || {message: undefined, code: undefined}
				throw new AuthenticationError(json.message, json.code)
			}

			if (response.status === 403) {
				const json = await response.json()
				throw new AuthorizationError(json.message, json.code)
			}

			if (response.status === 500) {
				const json = await response.json()
				throw new InternalError(json.message, json.code)
			}
			return response.json()
		})
		.then(json => {
			//成功状态
			if (json && json.status === 1) {
				return json.data
			}
			//内部错误
			if (json.code - 0 === 500) {
				throw new InternalError(json.message, json.code)
			}
			//业务异常
			if (!errorHandler) {
				message.error(`${json.message}(code:${json.code})`)
				throw new BusinessError(json.message, json.code)
			} else if (typeof errorHandler === "function") {
				errorHandler(json)
			} else {
				throw new BusinessError(json.message, json.code)
			}
		}).catch((e) => {
			//401异常系统全局处理
			if (e.name === AuthenticationError.NAME) {
				if (!window.authLock) {
					window.authLock = true
					sessionStorage.setItem('redirect_url', window.location)
					Modal.error({
						title: '提示',
						content: `${e.message}(code:${e.code})`,
						onOk: () => {
							window.location.href = "/login"
						}
					})
				}
				return Promise.reject()
			} else if (e.name === AuthorizationError.NAME) {
				Modal.error({
					title: '提示',
					content: `${e.message}(code:${e.code})`
				})
				return Promise.reject()
			} else if (e.name === BusinessError.NAME) {
				//如果接口调用自定义异常处理，抛出异常供接口调用者处理
				if (errorHandler) {
					throw e;
				}
			} else if (e.name === TimeOutError.NAME) {
				message.error(`请求超时,请联系管理员 [${e.message}]`)
				return Promise.reject()
			} else if (e.name === InternalError.NAME) {
				message.error(`系统内部错误,请联系管理员 [${e.message}]`)
				return Promise.reject()
			} else {
				message.error(`系统内部错误,请联系管理员 [${e.message}]`)
				return Promise.reject()
			}
		})
	return promise
}


function submitJSON(url, postData, method, errorHandler) {
	const headers = createTokenHeader({
		"Content-type": "application/json;charset=UTF-8"
	})
	return networkResponse(Promise.race([
			fetch(`${HOST}${url}`, {
				method: method,
				credentials: 'include',
				headers: headers,
				mode: "cors",
				body: JSON.stringify(postData || {})
			}),
			new Promise(function (resolve, reject) {
				setTimeout(() => reject(new TimeOutError('Request_Timeout')), 4000)
			})]),
		errorHandler
	)
}

function submitParam(url, postData, method, errorHandler) {
	//formData可能造成不能提交
	const formData = new FormData()
	Object.entries(postData || {}).forEach(([k, v]) => {
		formData.append(k, v)
	})
	const headers = createTokenHeader()
	let paramString
	if (postData) {
		paramString = createParamString(postData)
	}
	const getURL = paramString ? `${HOST}${url}?${paramString}` : `${HOST}${url}`
	return networkResponse(fetch(getURL, {
			method: method,
			credentials: "include",
			headers: headers,
			mode: "cors",
			// body: formData
		}),
		errorHandler)
}

function submitQueryString(url, params, method, errorHandler) {
	const headers = createTokenHeader()
	let paramString
	if (params) {
		paramString = createParamString(params)
	}
	const getURL = paramString ? `${HOST}${url}?${paramString}` : `${HOST}${url}`
	return networkResponse(fetch(getURL, {
			method: method,
			headers: headers,
			credentials: "include",
			mode: "cors",
		}),
		errorHandler)
}

export function postJSON(url, postData, errorHandler) {
	return submitJSON(url, postData, "POST", errorHandler)
}

export function postParam(url, postData, errorHandler) {
	return submitParam(url, postData || {}, "POST", errorHandler)
}

export function putJSON(url, postData, errorHandler) {
	return submitJSON(url, postData, "PUT", errorHandler)
}

export function putParam(url, postData, errorHandler) {
	return submitParam(url, postData, "PUT", errorHandler)
}

export function get(url, params, errorHandler) {
	return submitQueryString(url, params, "GET", errorHandler)
}

export function del(url, params, errorHandler) {
	return submitQueryString(url, params, "DELETE", errorHandler)
}

export const OK = 'OK'